package com.project.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.project.demo.entity.AccessToken;
import com.project.demo.entity.User;
import com.project.demo.entity.UserGroup;
import com.project.demo.service.AccessTokenService;
import com.project.demo.service.CosService;
import com.project.demo.service.UserGroupService;
import com.project.demo.service.UserService;

import com.project.demo.controller.base.BaseController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;

/**
 * 用户账户：用于保存用户登录信息(User)表控制层
 */
@Slf4j
@RestController
@RequestMapping("user")
public class UserController extends BaseController<User, UserService> {
    /**
     * 服务对象
     */
    @Autowired
    public UserController(UserService service) {
        setService(service);
    }

    /**
     * Token服务
     */
    @Autowired
    private AccessTokenService tokenService;

    @Autowired
    private UserGroupService userGroupService;
    
    @Autowired
    private CosService cosService;


    
    /**

    * 注册
     * @param data
     * @param request
     * @return
     */
    @PostMapping("register")
    public Map<String, Object> signUp(@RequestBody Map<String, Object> data, HttpServletRequest request) {
        log.info("[注册接口] 开始处理注册请求");
        log.info("[注册接口] 接收到的参数: {}", data);
        
        try {
            // 提取验证码参数
            String smsCode = (String) data.get("sms_code");
            String captcha = (String) data.get("captcha");
            String captchaId = (String) data.get("captcha_id");
            String phone = (String) data.get("phone");
            String username = (String) data.get("username");
            
            log.info("[注册接口] 验证码参数 - smsCode: {}, captcha: {}, captchaId: {}, phone: {}, username: {}", 
                smsCode != null ? "有值" : "null", 
                captcha != null ? "有值" : "null", 
                captchaId, phone, username);
            
            // 验证验证码
            if (smsCode != null && !smsCode.isEmpty()) {
                log.info("[注册接口] 使用短信验证码验证，手机号: {}", phone);
                // 手机注册：验证短信验证码
                String storedCode = (String) request.getSession().getAttribute("sms_code_" + phone);
                Long codeTime = (Long) request.getSession().getAttribute("sms_code_time_" + phone);
                
                log.info("[注册接口] Session中的验证码 - storedCode: {}, codeTime: {}", 
                    storedCode != null ? "有值" : "null", codeTime);
                
                if (storedCode == null || codeTime == null) {
                    log.warn("[注册接口] 验证码已过期或不存在");
                    return error(30000, "验证码已过期，请重新获取");
                }
                
                // 验证码5分钟有效
                if (System.currentTimeMillis() - codeTime > 5 * 60 * 1000) {
                    log.warn("[注册接口] 验证码已过期，时间差: {}ms", System.currentTimeMillis() - codeTime);
                    request.getSession().removeAttribute("sms_code_" + phone);
                    request.getSession().removeAttribute("sms_code_time_" + phone);
                    return error(30000, "验证码已过期，请重新获取");
                }
                
                if (!storedCode.equals(smsCode)) {
                    log.warn("[注册接口] 验证码错误 - 期望: {}, 实际: {}", storedCode, smsCode);
                    return error(30000, "验证码错误");
                }
                
                log.info("[注册接口] 短信验证码验证成功");
                // 验证成功后清除session中的验证码
                request.getSession().removeAttribute("sms_code_" + phone);
                request.getSession().removeAttribute("sms_code_time_" + phone);
            } else if (captcha != null && !captcha.isEmpty()) {
                log.info("[注册接口] 使用图形验证码验证");
                // 邮箱注册：验证图形验证码
                HttpSession session = request.getSession();
                String sessionKey = "captcha_" + (captchaId != null ? captchaId : session.getId());
                String sessionCode = (String) session.getAttribute(sessionKey);
                Long sessionTime = (Long) session.getAttribute(sessionKey + "_time");
                
                log.info("[注册接口] Session中的图形验证码 - sessionKey: {}, sessionCode: {}, sessionTime: {}", 
                    sessionKey, sessionCode != null ? "有值" : "null", sessionTime);
                
                if (sessionCode == null) {
                    log.warn("[注册接口] 图形验证码已过期或不存在");
                    return error(30000, "验证码已过期，请刷新验证码");
                }
                
                // 验证码5分钟有效
                if (sessionTime != null && System.currentTimeMillis() - sessionTime > 5 * 60 * 1000) {
                    log.warn("[注册接口] 图形验证码已过期，时间差: {}ms", System.currentTimeMillis() - sessionTime);
                    session.removeAttribute(sessionKey);
                    session.removeAttribute(sessionKey + "_time");
                    return error(30000, "验证码已过期，请刷新验证码");
                }
                
                // 验证码不区分大小写
                if (!sessionCode.equalsIgnoreCase(captcha)) {
                    log.warn("[注册接口] 图形验证码错误 - 期望: {}, 实际: {}", sessionCode, captcha);
                    return error(30000, "验证码错误");
                }
                
                log.info("[注册接口] 图形验证码验证成功");
                // 验证成功后删除验证码
                session.removeAttribute(sessionKey);
                session.removeAttribute(sessionKey + "_time");
            } else {
                log.warn("[注册接口] 验证码为空");
                return error(30000, "验证码不能为空");
            }
            
            log.info("[注册接口] 验证码验证成功，开始创建用户");
            
            // 验证码验证成功后，创建用户
            User user = new User();
            user.setUsername((String) data.get("username"));
            user.setPassword((String) data.get("password"));
            user.setNickname((String) data.get("nickname"));
            user.setEmail((String) data.get("email"));
            user.setPhone((String) data.get("phone"));
            
            // 设置用户组，默认为"普通用户"
            String userGroup = (String) data.get("user_group");
            if (userGroup == null || userGroup.isEmpty()) {
                userGroup = "普通用户";
            }
            user.setUserGroup(userGroup);
            
            log.info("[注册接口] 创建用户对象 - username: {}, userGroup: {}, email: {}, phone: {}", 
                user.getUsername(), user.getUserGroup(), user.getEmail(), user.getPhone());
            
            // 查询用户是否已存在
            Map<String, String> query = new HashMap<>();
            query.put("username", user.getUsername());
            List userList = service.select(query, new HashMap<>()).getResultList();
            if (userList.size() > 0) {
                log.warn("[注册接口] 用户已存在: {}", user.getUsername());
                return error(30000, "用户已存在");
            }
            
            // 设置用户ID为null，让数据库自动生成
            user.setUserId(null);
            // 加密密码
            if (user.getPassword() != null && !user.getPassword().isEmpty()) {
                user.setPassword(service.encryption(user.getPassword()));
            } else {
                log.error("[注册接口] 密码为空");
                return error(30000, "密码不能为空");
            }
            // 设置用户默认状态为可用
            if (user.getState() == null) {
                user.setState(1);
            }
            
            log.info("[注册接口] 准备保存用户到数据库");
            
            // 保存用户到数据库
            try {
                service.save(user);
                log.info("[注册接口] 用户注册成功: username={}, userGroup={}, userId={}", 
                    user.getUsername(), user.getUserGroup(), user.getUserId());
                
                // 返回成功结果，包含用户信息
                JSONObject userObj = JSONObject.parseObject(JSONObject.toJSONString(user));
                userObj.remove("password"); // 移除密码，不返回给前端
                return success(userObj);
            } catch (Exception saveException) {
                log.error("[注册接口] 保存用户到数据库失败", saveException);
                log.error("[注册接口] 异常详情", saveException);
                return error(30000, "注册失败：" + saveException.getMessage());
            }
        } catch (Exception e) {
            log.error("[注册接口] 注册失败，发生异常", e);
            log.error("[注册接口] 异常堆栈", e);
            return error(30000, "注册失败：" + e.getMessage());
        }
    }

    /**
     * 找回密码
     * @param form
     * @return
     */
    @PostMapping("forget_password")
    public Map<String, Object> forgetPassword(@RequestBody User form,HttpServletRequest request) {
        JSONObject ret = new JSONObject();
        String username = form.getUsername();
        String code = form.getCode();
        String password = form.getPassword();
        // 判断条件
        if(code == null || code.length() == 0){
            return error(30000, "验证码不能为空");
        }
        if(username == null || username.length() == 0){
            return error(30000, "用户名不能为空");
        }
        if(password == null || password.length() == 0){
            return error(30000, "密码不能为空");
        }

        // 查询用户
        Map<String, String> query = new HashMap<>();
        query.put("username",username);
        Query select = service.select(query, service.readConfig(request));
        List list = select.getResultList();
        if (list.size() > 0) {
            User o = (User) list.get(0);
            JSONObject query2 = new JSONObject();
            JSONObject form2 = new JSONObject();
            // 修改用户密码
            query2.put("user_id",o.getUserId());
            form2.put("password",service.encryption(password));
            service.update(query, service.readConfig(request), form2);
            return success(1);
        }
        return error(70000,"用户不存在");
    }

    /**
     * 登录
     * @param data
     * @param httpServletRequest
     * @return
     */
    @PostMapping("login")
    public Map<String, Object> login(@RequestBody Map<String, String> data, HttpServletRequest httpServletRequest) {
        log.info("[执行登录接口]");

        String username = data.get("username");
        String email = data.get("email");
        String phone = data.get("phone");
        String password = data.get("password");

        List resultList = null;
        Map<String, String> map = new HashMap<>();
        if(username != null && "".equals(username) == false){
            map.put("username", username);
            resultList = service.select(map, new HashMap<>()).getResultList();
        }
        else if(email != null && "".equals(email) == false){
            map.put("email", email);
            resultList = service.select(map, new HashMap<>()).getResultList();
        }
        else if(phone != null && "".equals(phone) == false){
            map.put("phone", phone);
            resultList = service.select(map, new HashMap<>()).getResultList();
        }else{
            return error(30000, "账号或密码不能为空");
        }
        if (resultList == null || password == null) {
            return error(30000, "账号或密码不能为空");
        }
        //判断是否有这个用户
        if (resultList.size()<=0){
            return error(30000,"用户不存在");
        }

        User byUsername = (User) resultList.get(0);


        Map<String, String> groupMap = new HashMap<>();
        groupMap.put("name",byUsername.getUserGroup());
        List groupList = userGroupService.select(groupMap, new HashMap<>()).getResultList();
        if (groupList.size()<1){
            return error(30000,"用户组不存在");
        }

        UserGroup userGroup = (UserGroup) groupList.get(0);

        //查询用户审核状态
        if (!StringUtils.isEmpty(userGroup.getSourceTable())){
            String sql = "select examine_state from "+ userGroup.getSourceTable() +" WHERE user_id = " + byUsername.getUserId();
            String res = String.valueOf(service.runCountSql(sql).getSingleResult());
            if (res==null){
                return error(30000,"用户不存在");
            }
            if (!res.equals("已通过")){
                return error(30000,"该用户审核未通过");
            }
        }

        //查询用户状态
        if (byUsername.getState()!=1){
            return error(30000,"用户非可用状态，不能登录");
        }

        String md5password = service.encryption(password);
        if (byUsername.getPassword().equals(md5password)) {
            // 存储Token到数据库
            AccessToken accessToken = new AccessToken();
            accessToken.setToken(UUID.randomUUID().toString().replaceAll("-", ""));
            accessToken.setUser_id(byUsername.getUserId());
            tokenService.save(accessToken);

            // 返回用户信息
            JSONObject user = JSONObject.parseObject(JSONObject.toJSONString(byUsername));
            user.put("token", accessToken.getToken());
            JSONObject ret = new JSONObject();
            ret.put("obj",user);
            return success(ret);
        } else {
            return error(30000, "账号或密码不正确");
        }
    }

    /**
     * 修改密码
     * @param data
     * @param request
     * @return
     */
    @PostMapping("change_password")
    public Map<String, Object> change_password(@RequestBody Map<String, String> data, HttpServletRequest request){
        // 根据Token获取UserId
        String token = request.getHeader("x-auth-token");
        Integer userId = tokenGetUserId(token);
        // 根据UserId和旧密码获取用户
        Map<String, String> query = new HashMap<>();
        String o_password = data.get("o_password");
        query.put("user_id" ,String.valueOf(userId));
        query.put("password" ,service.encryption(o_password));
        Query ret = service.count(query, service.readConfig(request));
        List list = ret.getResultList();
        Object s = list.get(0);
        int count = Integer.parseInt(list.get(0).toString());
        if(count > 0){
            // 修改密码
            Map<String,Object> form = new HashMap<>();
            form.put("password",service.encryption(data.get("password")));
            service.update(query,service.readConfig(request),form);
            return success(1);
        }
        return error(10000,"密码修改失败！");
    }

    /**
     * 登录态
     * @param request
     * @return
     */
    @GetMapping("state")
    public Map<String, Object> state(HttpServletRequest request) {
        JSONObject ret = new JSONObject();
        // 获取状态
        String token = request.getHeader("x-auth-token");

        // 根据登录态获取用户ID
        Integer userId = tokenGetUserId(token);

        log.info("[返回userId] {}",userId);
        if(userId == null || userId == 0){
            return error(10000,"用户未登录!");
        }

        // 根据用户ID获取用户
        Map<String,String> query = new HashMap<>();
        query.put("user_id" ,String.valueOf(userId));

        // 根据用户ID获取
        Query select = service.select(query,service.readConfig(request));
        List resultList = select.getResultList();
        if (resultList.size() > 0) {
            JSONObject user = JSONObject.parseObject(JSONObject.toJSONString(resultList.get(0)));
            user.put("token",token);
            ret.put("obj",user);
            return success(ret);
        } else {
            return error(10000,"用户未登录!");
        }
    }

    /**
     * 登录态
     * @param request
     * @return
     */
    @GetMapping("quit")
    public Map<String, Object> quit(HttpServletRequest request) {
        String token = request.getHeader("x-auth-token");
        JSONObject ret = new JSONObject();
        Map<String, String> query = new HashMap<>(16);
        query.put("token", token);
        try{
            tokenService.delete(query,service.readConfig(request));
        }catch (Exception e){
            e.printStackTrace();
        }
        return success("退出登录成功！");
    }

    /**
     * 获取登录用户ID
     * @param token
     * @return
     */
    public Integer tokenGetUserId(String token) {
        log.info("[获取的token] {}",token);
        // 根据登录态获取用户ID
        if(token == null || "".equals(token)){
            return 0;
        }
        Map<String, String> query = new HashMap<>(16);
        query.put("token", token);
        AccessToken byToken = tokenService.findOne(query);
        if(byToken == null){
            return 0;
        }
        return byToken.getUser_id();
    }

    /**
     * 重写add
     * @return
     */
    @PostMapping("/add")
    @Transactional
    public Map<String, Object> add(HttpServletRequest request) throws IOException {
        Map<String,Object> map = service.readBody(request.getReader());
        map.put("password",service.encryption(String.valueOf(map.get("password"))));
        service.insert(map);
        return success(1);
    }

    /**
     * 发送短信验证码
     * @param data
     * @return
     */
    @PostMapping("send_sms")
    public Map<String, Object> sendSms(@RequestBody Map<String, String> data, HttpServletRequest request) {
        String phone = data.get("phone");
        if (phone == null || phone.isEmpty()) {
            return error(30000, "手机号码不能为空");
        }
        
        // TODO: 集成真实的短信服务（如阿里云、腾讯云等）
        // 这里暂时模拟发送验证码，实际应该调用短信服务API
        // 验证码应该存储在session或缓存中，并设置过期时间（如5分钟）
        
        // 生成6位随机验证码
        String code = String.valueOf((int)((Math.random() * 9 + 1) * 100000));
        
        // 将验证码存储到session中
        request.getSession().setAttribute("sms_code_" + phone, code);
        request.getSession().setAttribute("sms_code_time_" + phone, System.currentTimeMillis());
        
        log.info("发送短信验证码到手机号: {}, 验证码: {}", phone, code);
        
        // 实际项目中应该调用短信服务发送验证码
        // 这里仅返回成功，实际验证码应该通过短信发送给用户
        
        return success(1);
    }

    /**
     * 手机快捷登录
     * @param data
     * @param request
     * @return
     */
    @PostMapping("phone_login")
    public Map<String, Object> phoneLogin(@RequestBody Map<String, String> data, HttpServletRequest request) {
        String phone = data.get("phone");
        String smsCode = data.get("sms_code");
        
        if (phone == null || phone.isEmpty()) {
            return error(30000, "手机号码不能为空");
        }
        if (smsCode == null || smsCode.isEmpty()) {
            return error(30000, "验证码不能为空");
        }
        
        // 验证验证码
        String storedCode = (String) request.getSession().getAttribute("sms_code_" + phone);
        Long codeTime = (Long) request.getSession().getAttribute("sms_code_time_" + phone);
        
        if (storedCode == null || codeTime == null) {
            return error(30000, "验证码已过期，请重新获取");
        }
        
        // 验证码5分钟有效
        if (System.currentTimeMillis() - codeTime > 5 * 60 * 1000) {
            request.getSession().removeAttribute("sms_code_" + phone);
            request.getSession().removeAttribute("sms_code_time_" + phone);
            return error(30000, "验证码已过期，请重新获取");
        }
        
        if (!storedCode.equals(smsCode)) {
            return error(30000, "验证码错误");
        }
        
        // 验证码验证成功后，清除session中的验证码
        request.getSession().removeAttribute("sms_code_" + phone);
        request.getSession().removeAttribute("sms_code_time_" + phone);
        
        // 根据手机号查找用户
        Map<String, String> query = new HashMap<>();
        query.put("phone", phone);
        List resultList = service.select(query, new HashMap<>()).getResultList();
        
        if (resultList.size() == 0) {
            return error(30000, "用户不存在");
        }
        
        User user = (User) resultList.get(0);
        
        // 查询用户状态
        if (user.getState() != 1) {
            return error(30000, "用户非可用状态，不能登录");
        }
        
        // 存储Token到数据库
        AccessToken accessToken = new AccessToken();
        accessToken.setToken(UUID.randomUUID().toString().replaceAll("-", ""));
        accessToken.setUser_id(user.getUserId());
        tokenService.save(accessToken);
        
        // 返回用户信息
        JSONObject userObj = JSONObject.parseObject(JSONObject.toJSONString(user));
        userObj.put("token", accessToken.getToken());
        JSONObject ret = new JSONObject();
        ret.put("obj", userObj);
        return success(ret);
    }
    
    /**
     * 用户上传接口（支持头像上传）
     */
    @PostMapping("/upload")
    public Map<String, Object> upload(@RequestParam("file") MultipartFile file) {
        log.info("用户上传接口被调用");
        if (file.isEmpty()) {
            return error(30000, "没有选择文件");
        }
        try {
            // 使用腾讯云COS上传
            String fileUrl = cosService.uploadFile(file);
            
            log.info("用户文件上传成功，URL: {}", fileUrl);
            
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("url", fileUrl);
            return success(jsonObject);
        } catch (Exception e) {
            log.error("用户COS上传失败：{}", e.getMessage(), e);
            // 如果COS上传失败，尝试本地存储作为备用方案
            try {
                String userDir = System.getProperty("user.dir");
                String filePath;
                if (userDir.endsWith("server")) {
                    filePath = userDir + "\\target\\classes\\static\\upload\\";
                } else {
                    filePath = userDir + "\\server\\target\\classes\\static\\upload\\";
                }
                java.io.File targetDir = new java.io.File(filePath);
                if (!targetDir.exists() && !targetDir.isDirectory()) {
                    targetDir.mkdirs();
                }
                String fileName = file.getOriginalFilename();
                java.io.File dest = new java.io.File(filePath + fileName);
                file.transferTo(dest);
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("url", "/api/upload/" + fileName);
                log.warn("用户COS上传失败，使用本地存储备用方案");
                return success(jsonObject);
            } catch (java.io.IOException ioException) {
                log.error("用户本地存储也失败：{}", ioException.getMessage(), ioException);
            }
        }
        return error(30000, "上传失败");
    }

}
